/**
* MythBOINC is a BOINC plugin for MythTV, it allows for BOINC Client management via the MythTV interface.
* Copyright (C) 2008  Kenneth Dixon
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#ifndef MYTHBOINCCONFIG_CPP
#define MYTHBOINCCONFIG_CPP

/* MythTV includes */
#include <mythtv/mythcontext.h>

/* Custom includes */
#include "mythboincconfig.h"
#include <sstream>
#include "/usr/include/pstreams/pstream.h"

using namespace std;


/*************************************************************************************************/


MythBoincClientsConfig::MythBoincClientsConfig()
{
    
    boincClientVCG = new VerticalConfigurationGroup(false); 
    LoadPage(4); 
      
}


MythBoincClientsConfig::~MythBoincClientsConfig()
{
    
    ///delete stuff
    
}


string MythBoincClientsConfig::IntToString(int inInt)
{
    
    stringstream ss;
    ss<<inInt;
    string outResult;
    ss>>outResult;
    
    return(outResult);
     
}


HostLineEdit *MythBoincClientsConfig::BoincClientIpTXT(int ID)
{
    
    HostLineEdit *boincClientIP = new HostLineEdit("BoincClentIP"+IntToString(ID));
    boincClientIP->setLabel(QObject::tr("IP Address"));
    boincClientIP->setValue("");
    boincClientIP->setHelpText(QObject::tr("Enter the IP adress of the BOINC Client you wish to connect to.\n i.e. localhost, 127.0.0.1, 192.168.0.5"));
    return(boincClientIP);
    
}


HostLineEdit *MythBoincClientsConfig::BoincClientPwdTXT(int ID)
{
    
    HostLineEdit *boincClientPwd = new HostLineEdit("BoincClentPwd"+IntToString(ID));
    boincClientPwd->setLabel(QObject::tr("Password"));
    boincClientPwd->SetPasswordEcho(true);
    boincClientPwd->setValue("");
    boincClientPwd->setHelpText(QObject::tr("Enter the password for the BOINC Client instance,\n it can be found/set in /var/lib/boinc-client/gui_rpc_auth.cfg file and is empty by default"));
    return(boincClientPwd);
    
}


ButtonSetting *MythBoincClientsConfig::BoincClientEditBTN(int ID)
{ 
      
    TransButtonSetting *BoincClientEditBTN = new TransButtonSetting(IntToString(ID));    
    BoincClientEditBTN->setLabel(QObject::tr("Edit"));
    BoincClientEditBTN->setHelpText("Edit the settings (attach/detach projects) for this BOINC Client");
    connect(BoincClientEditBTN, SIGNAL(pressed(QString)), this, SLOT(editBtnPress(QString)));

    return(BoincClientEditBTN);
    
}


void MythBoincClientsConfig::LoadPage(int numOfClients)
{
    
    for(int i=0; i<numOfClients; i++)
    {
        AddClient(i);
        AttachClient(i);
    }
    
    addChild(boincClientVCG);
    
}


void MythBoincClientsConfig::AddClient(int ID)
{
    
    BoincClientIpTXTVEC.push_back(BoincClientIpTXT(ID));
    BoincClientPwdTXTVEC.push_back(BoincClientPwdTXT(ID));
    BoincClientEditBTNVEC.push_back(BoincClientEditBTN(ID));
    
}


void MythBoincClientsConfig::AttachClient(int ID)
{
    
    boincClientVCG->setLabel(QObject::tr("MythBOINC Client Settings"));
    
    HorizontalConfigurationGroup *boincClientHCG0 = new HorizontalConfigurationGroup(false);
    HorizontalConfigurationGroup *boincClientHCG1 = new HorizontalConfigurationGroup(false);
        
    boincClientHCG0->addChild(BoincClientIpTXTVEC.at(ID));
    boincClientHCG0->addChild(BoincClientPwdTXTVEC.at(ID));
    boincClientHCG1->addChild(BoincClientEditBTNVEC.at(ID));

    boincClientVCG->addChild(boincClientHCG0);
    boincClientVCG->addChild(boincClientHCG1); 
         
}


bool MythBoincClientsConfig::TestClientConnection(QString ID)
{
    
    bool result;
    vector<string> commandString;
    redi::ipstream in;
    redi::ipstream in2;
    
    //command
    in.open("which boinc_cmd");

    getline(in, cmd);
    if(!cmd.empty())
    {
        commandString.push_back(cmd);
        
        //host
        commandString.push_back("--host");
        commandString.push_back(BoincClientIpTXTVEC.at(ID.toInt())->getValue());
        
        //password
        commandString.push_back("--passwd");
        commandString.push_back(BoincClientPwdTXTVEC.at(ID.toInt())->getValue());
        
        //argument
        commandString.push_back("--get_state");
        
        //execute
        in2.open("boinc_cmd", commandString, redi::pstreambuf::pstderr);
        
        string errOutputLine;
        getline(in2.err(), errOutputLine);
        if(!errOutputLine.empty())
        {
            if(errOutputLine == "Authorization failure: -155")
            {   
                //VERBOSE(VB_IMPORTANT, "Invalid Password!!!");
                DialogBox("Invalid Password!!!");
            }
            else if(errOutputLine == "connect: No route to host")
            {
                //VERBOSE(VB_IMPORTANT, "Invalid IP Address: "+errOutputLine); 
                DialogBox("Invalid IP Address: \n\n"+errOutputLine);
            }
            else if(errOutputLine == "gethostbyname: Connection timed out")
            {
                //VERBOSE(VB_IMPORTANT, "Invalid host Name: "+errOutputLine);
                DialogBox("Invalid host Name: \n\n"+errOutputLine);
            }
            else if(errOutputLine == "connect: Connection refused")
            {
               //VERBOSE(VB_IMPORTANT, "No connection found: "+errOutputLine);
               DialogBox("No connection, is your boinc-client daemon running?: \n\n"+errOutputLine);
            }  
            else if(errOutputLine == "Authorization failure: -102")
            {
                //VERBOSE(VB_IMPORTANT, "No connection found: "+errOutputLine);
                DialogBox("Authorization problem, try adding this computers IP address to /etc/boinc-client/remote_hosts.cfg of the destination machine, then restart boinc-client: \n\n"+errOutputLine);
            } 
            else
            {
                //VERBOSE(VB_IMPORTANT, "Unknown connection error: "+errOutputLine);
                DialogBox("Unknown connection error: \n\n"+errOutputLine);
            }
            
            result = false;
        }
        else
        {
            //VERBOSE(VB_IMPORTANT, "No connection error detected");
            result = true;
        }
    }
    else
    {   
        //VERBOSE(VB_IMPORTANT, "boinc_cmd does not exist!!");
        DialogBox("boinc_cmd not found make sure BOINC Client package is installed");
        result = false;   
    }
    in.close();
    in2.close();
    return(result);
    
}


void MythBoincClientsConfig::DialogBox(QString msg)
{
    
    MythPopupBox::showOkPopup
    (
        gContext->GetMainWindow(),
        QObject::tr("Event"),
        QString(QObject::tr(msg)),
        "OK"
    );
    
}


void MythBoincClientsConfig::editBtnPress(QString ID)
{

/*
    AddClient(2);
    HorizontalConfigurationGroup *boincClientHCG2 = new HorizontalConfigurationGroup(false);
        
    boincClientHCG2->addChild(BoincClientIpTXTVEC.at(2));
    boincClientHCG2->addChild(BoincClientPwdTXTVEC.at(2));

    boincClientVCG->addChild(boincClientHCG2);
    //this->removeChild(boincClientVCG);
    this->addChild(boincClientVCG);
*/    

    if(TestClientConnection(ID))
    {
        MythBoincClientConfig* boincClientConfig = new MythBoincClientConfig
        (
            cmd,
            BoincClientIpTXTVEC.at(ID.toInt())->getValue(),
            BoincClientPwdTXTVEC.at(ID.toInt())->getValue()
        );
                                                            
        boincClientConfig->exec();   
        delete boincClientConfig;
    }
    else
    {
        VERBOSE(VB_IMPORTANT, "Connection Error!!");  
    }
}


/*************************************************************************************************/


MythBoincClientConfig::MythBoincClientConfig(QString inCmd, QString inIP, QString inPwd)
{
    
    //VERBOSE(VB_IMPORTANT, "Loading indervidual client config page for "+inID);
    //VERBOSE(VB_IMPORTANT, "BOINC Client IP: "+inIP);
    //VERBOSE(VB_IMPORTANT, "BOINC Client password: "+inPwd);  
    
    cmd = inCmd;
    ip = inIP;
    pwd = inPwd;
    
    //LoadMgrPage();
    LoadDetachPage();
    LoadAttachPage(); 

}


MythBoincClientConfig::~MythBoincClientConfig()
{
    ///delete stuff
}


string MythBoincClientConfig::IntToString(int inInt)
{
    
    stringstream ss;
    ss<<inInt;
    string outResult;
    ss>>outResult;
    
    return(outResult); 
    
}


void MythBoincClientConfig::LoadAttachPage()
{
    
    VerticalConfigurationGroup *boincProjectAttachVCG = new VerticalConfigurationGroup(false);
    boincProjectAttachVCG->setLabel(QObject::tr("MythBOINC Project Attach for: "+ip));
   
    PopulateProjectDetails();
    boincProjectAttachVCG->addChild(ProjectAttachURLCBX());
    boincProjectAttachVCG->addChild(ProjectAttachCustURLTXT());
    boincProjectAttachVCG->addChild(ProjectAttachEmailTXT());
    boincProjectAttachVCG->addChild(ProjectAttachPwdTXT());
    boincProjectAttachVCG->addChild(ProjectAttachUsrTXT());
    boincProjectAttachVCG->addChild(ProjectAttachBTN()); 
    
    this->addChild(boincProjectAttachVCG);   
     
}


void MythBoincClientConfig::PopulateProjectDetails()
{
    vector<QString> tempVec;
    
    tempVec.push_back("CUSTOM - Enter URL Below");
    tempVec.push_back("CUSTOM");
    tempVec.push_back("Add a custom project, the project must support remote account activation");
    projectDetails.push_back(tempVec);
    tempVec.clear();
    
    tempVec.push_back("climateprediction.net");
    tempVec.push_back("http://climateprediction.net");
    tempVec.push_back("Climateprediction.net is the largest experiment to try and produce a forecast of the climate in the 21st century.");
    projectDetails.push_back(tempVec);
    tempVec.clear();
    
    tempVec.push_back("SZTAKI Desktop Grid");
    tempVec.push_back("http://szdg.lpds.sztaki.hu/szdg/");
    tempVec.push_back("SZTAKI Desktop Grid currently searches for generalized binary number systems.");
    projectDetails.push_back(tempVec);
    tempVec.clear();
        
    tempVec.push_back("Prime Grid");
    tempVec.push_back("http://www.primegrid.com");
    tempVec.push_back("Prime Numbers are of great interest to mathematicians for a variety of reasons. Primes also play a central role in the cryptographic systems which are used for computer security.");
    projectDetails.push_back(tempVec);
    tempVec.clear();    
    
    tempVec.push_back("ABC@home");
    tempVec.push_back("http://abcathome.com/");
    tempVec.push_back("The ABC conjecture involves abc-triples. The ABC conjecture is currently one of the greatest open problems in mathematics. If it is proven to be true, a lot of other open problems can be answered directly from it.");
    projectDetails.push_back(tempVec);
    tempVec.clear(); 
        
    tempVec.push_back("SHA-1 Collision Search Graz");
    tempVec.push_back("http://boinc.iaik.tugraz.at/sha1_coll_search/");
    tempVec.push_back("SHA-1 Collision Search Graz is a research project researching cryptanalysis. Cryptanalysis is the study of methods for obtaining the meaning of encrypted information, without access to the secret information which is normally required to do so.");
    projectDetails.push_back(tempVec);
    tempVec.clear();
            
    tempVec.push_back("Einstein@Home");
    tempVec.push_back("http://einstein.phys.uwm.edu/");
    tempVec.push_back("The Einstein@Home project searches for continuous wave sources of gravitational radiation. A successful detection of gravitational waves would constitute a significant milestone in physics, as it would be the first detection of a previously unknown astronomical object by means of gravitational radiation alone.");
    projectDetails.push_back(tempVec);
    tempVec.clear();
                
    tempVec.push_back("Rectilinear Crossing Number");
    tempVec.push_back("http://dist.ist.tugraz.at/cape5/");
    tempVec.push_back("Many questions in computational and combinatorial geometry are based on finite sets of points in the Euclidean plane. Several problems from graph theory also fit into this framework, when edges are restricted to be straight.");
    projectDetails.push_back(tempVec);
    tempVec.clear();
                 
    tempVec.push_back("LHC@home");
    tempVec.push_back("http://lhcathome.cern.ch/lhcathome/");
    tempVec.push_back("It is considered an effort to help build the Large Hadron Collider. The project software involves a program called SixTrack which simulates particles accelerating through the 27 km (17 mile)-long LHC to find their orbit stability.");
    projectDetails.push_back(tempVec);
    tempVec.clear();
                  
    tempVec.push_back("The Lattice Project");
    tempVec.push_back("http://boinc.umiacs.umd.edu/");
    tempVec.push_back("Scientific research can be greatly enhanced with access to high performance computing resources. The computational environment in which many scientists work is substantively deficient, materially impeding progress in a number of fields. It is our goal to make sufficient computational and data resources available to an active community of scientific researchers.");
    projectDetails.push_back(tempVec);
    tempVec.clear();
                  
    tempVec.push_back("Proteins@Home");
    tempVec.push_back("http://biology.polytechnique.fr/proteinsathome");
    tempVec.push_back("Proteins@Home is a large-scale non-profit protein structure prediction project utilizing distributed computing to perform a lot of computations in a small amount of time.");
    projectDetails.push_back(tempVec);
    tempVec.clear();
                    
    tempVec.push_back("NQueens@Home");
    tempVec.push_back("http://nqueens.ing.udec.cl/");
    tempVec.push_back("This project uses Internet-connected computers to solve the N Queens problem.");
    projectDetails.push_back(tempVec);
    tempVec.clear();
                     
    tempVec.push_back("Quantum Monte Carlo at Home");
    tempVec.push_back("http://qah.uni-muenster.de/");
    tempVec.push_back("We live in a world full of molecules and reactions between molecules are the essential phenomena behind all life processes. With this in mind one can imagine the great importance that knowledge about molecular structure inheres, and also the usefulness of the ability to make accurate predictions about molecular reactivity.");
    projectDetails.push_back(tempVec);
    tempVec.clear();
                       
    tempVec.push_back("SETI@home");
    tempVec.push_back("http://setiathome.berkeley.edu/");
    tempVec.push_back("SETI@home searches for possible evidence of radio transmissions from extraterrestrial intelligence using observational data from the Arecibo radio telescope.");
    projectDetails.push_back(tempVec);
    tempVec.clear();
                        
    tempVec.push_back("Leiden Classical");
    tempVec.push_back("http://boinc.gorlaeus.net/");
    tempVec.push_back("Leiden Classical is a Desktop Computer Grid dedicated to general Classical Dynamics for any scientist or science student! Classical Dynamics is used for describing the motion of a variety of different macroscopic objects.");
    projectDetails.push_back(tempVec);
    tempVec.clear();
                         
    tempVec.push_back("Spinhenge@home");
    tempVec.push_back("http://spin.fh-bielefeld.de/");
    tempVec.push_back("This project uses the Metropolis Monte Carlo algorithm to calculate and simulate spin dynamics in nanoscale molecular magnets.");
    projectDetails.push_back(tempVec);
    tempVec.clear();
                           
    tempVec.push_back("uFluids@home");
    tempVec.push_back("http://www.ufluids.net/");
    tempVec.push_back("μFluids project is a massively distributed computer simulation of two-phase fluid behavior in microgravity and microfluidics problems. Our goal is to design better satellite propellant management devices and address two-phase flow in microchannel and MEMS devices.");
    projectDetails.push_back(tempVec);
    tempVec.clear();
                            
    tempVec.push_back("malariacontrol.net");
    tempVec.push_back("http://www.malariacontrol.net");
    tempVec.push_back("Stochastic modelling of the clinical epidemiology and natural history of Plasmodium falciparum malaria.");
    projectDetails.push_back(tempVec);
    tempVec.clear();
                            
    tempVec.push_back("Rosetta@home");
    tempVec.push_back("http://boinc.bakerlab.org/rosetta/");
    tempVec.push_back("Rosetta@home needs your help to determine the 3-dimensional shapes of proteins in research that may ultimately lead to finding cures for some major human diseases.");
    projectDetails.push_back(tempVec);
    tempVec.clear();
                            
    tempVec.push_back("Similarity Matrix of Proteins");
    tempVec.push_back("http://boinc.bio.wzw.tum.de/boincsimap/");
    tempVec.push_back("SIMAP is a public database of pre-calculated protein similarities that plays a key role in many bioinformatics methods. Please help to update SIMAP by calculating protein similarities on your computer.");
    projectDetails.push_back(tempVec);
    tempVec.clear();
                             
    tempVec.push_back("Superlink@Technion");
    tempVec.push_back("http://cbl-boinc-server2.cs.technion.ac.il/superlinkattechnion/");
    tempVec.push_back("Superlink@Technion helps geneticists all over the world find disease-provoking genes causing some types of diabetes, hypertension (high blood pressure), cancer, schizophrenia and many others. ");
    projectDetails.push_back(tempVec);
    tempVec.clear();
                             
    tempVec.push_back("PS3GRID.net");
    tempVec.push_back("http://www.ps3grid.net/");
    tempVec.push_back("If you enjoy science, you can participate by donating computing time to high-performance all-atom biomolecular simulations");
    projectDetails.push_back(tempVec);
    tempVec.clear();
        
}


HostComboBox *MythBoincClientConfig::ProjectAttachURLCBX()
{
    
    ProjectAttachURL = new HostComboBox("ProjectURL");
    ProjectAttachURL->setLabel(QObject::tr("Project URL"));
    //ProjectAttachURL->
    
    
    for(unsigned i=0;i < projectDetails.size(); i++)
    {
        ProjectAttachURL->addSelection(QObject::tr(projectDetails.at(i).at(0)), IntToString(i));
    }
//    ProjectAttachURL->addSelection(QObject::tr("CUSTOM - Enter URL Below"), "CUSTOM");
//    ProjectAttachURL->addSelection(QObject::tr("climateprediction.net"), "http://climateprediction.net");
//    ProjectAttachURL->addSelection(QObject::tr("SZTAKI Desktop Grid"), "http://szdg.lpds.sztaki.hu/szdg/");
//    ProjectAttachURL->addSelection(QObject::tr("Prime Grid"), "http://www.primegrid.com");
//    ProjectAttachURL->addSelection(QObject::tr("ABC@home"), "http://abcathome.com/");
//    ProjectAttachURL->addSelection(QObject::tr("SHA-1 Collision Search Graz"), "http://boinc.iaik.tugraz.at/sha1_coll_search/");
//    ProjectAttachURL->addSelection(QObject::tr("Einstein@Home"), "http://einstein.phys.uwm.edu/");
//    ProjectAttachURL->addSelection(QObject::tr("Rectilinear Crossing Number"), "http://dist.ist.tugraz.at/cape5/");
//    ProjectAttachURL->addSelection(QObject::tr("LHC@home"), "http://lhcathome.cern.ch/lhcathome/");
//    ProjectAttachURL->addSelection(QObject::tr("The Lattice Project"), "http://boinc.umiacs.umd.edu/");
//    ProjectAttachURL->addSelection(QObject::tr("Proteins@Home"), "http://biology.polytechnique.fr/proteinsathome");
//    ProjectAttachURL->addSelection(QObject::tr("NQueens@Home"), "http://nqueens.ing.udec.cl/");
//    ProjectAttachURL->addSelection(QObject::tr("Quantum Monte Carlo at Home"), "http://qah.uni-muenster.de/");
//    ProjectAttachURL->addSelection(QObject::tr("SETI@home"), "http://setiathome.berkeley.edu/");
//    ProjectAttachURL->addSelection(QObject::tr("Leiden Classical"), "http://boinc.gorlaeus.net/");
//    ProjectAttachURL->addSelection(QObject::tr("Spinhenge@home"), "http://spin.fh-bielefeld.de/");
//    ProjectAttachURL->addSelection(QObject::tr("uFluids@home"), "http://www.ufluids.net/");
//    ProjectAttachURL->addSelection(QObject::tr("malariacontrol.net"), "http://www.malariacontrol.net");
//    ProjectAttachURL->addSelection(QObject::tr("Rosetta@home"), "http://boinc.bakerlab.org/rosetta/");
//    ProjectAttachURL->addSelection(QObject::tr("Similarity Matrix of Proteins"), "http://boinc.bio.wzw.tum.de/boincsimap/");
//    ProjectAttachURL->addSelection(QObject::tr("Superlink@Technion"), "http://cbl-boinc-server2.cs.technion.ac.il/superlinkattechnion/");
//    ProjectAttachURL->addSelection(QObject::tr("PS3GRID.net"), "http://www.ps3grid.net/");
    
    ProjectAttachURL->setHelpText(QObject::tr("Select a project you wish to contribute to, or custom to enter your own"));
    
    connect(ProjectAttachURL, SIGNAL(valueChanged(const QString&)), this, SLOT(projectChanged(const QString&)));
    
    return(ProjectAttachURL);
    
}


HostLineEdit *MythBoincClientConfig::ProjectAttachCustURLTXT()
{
    
    ProjectAttachCustURL = new HostLineEdit("ProjectCustURL");
    ProjectAttachCustURL->setLabel(QObject::tr("Custom Project URL"));
    ProjectAttachCustURL->setHelpText(QObject::tr("Enter the Master URL for a project, make sure the combobox above has 'Custom' selected"));
    
    return(ProjectAttachCustURL);
    
}


HostLineEdit *MythBoincClientConfig::ProjectAttachEmailTXT()
{
    
    ProjectAttachEmail = new HostLineEdit("ProjectEmail");
    ProjectAttachEmail->setLabel(QObject::tr("Account Email"));
    ProjectAttachEmail->setHelpText(QObject::tr("Enter the email for your project account, one will be created if it does not exist"));
    
    return(ProjectAttachEmail);
    
}


HostLineEdit *MythBoincClientConfig::ProjectAttachPwdTXT()
{
    
    ProjectAttachPwd = new HostLineEdit("ProjectPwd");
    ProjectAttachPwd->SetPasswordEcho(true);
    ProjectAttachPwd->setLabel(QObject::tr("Account Password"));
    ProjectAttachPwd->setHelpText(QObject::tr("Enter the password for the account"));
    
    return(ProjectAttachPwd);
    
}


HostLineEdit *MythBoincClientConfig::ProjectAttachUsrTXT()
{
    
    ProjectAttachUsr = new HostLineEdit("ProjectUsr");
    ProjectAttachUsr->setLabel(QObject::tr("Account User Name"));
    ProjectAttachUsr->setHelpText(QObject::tr("Enter the user name you wish to use for this account"));
    
    return(ProjectAttachUsr);
    
}


ButtonSetting *MythBoincClientConfig::ProjectAttachBTN()
{
       
    TransButtonSetting *ProjectAttachBTN = new TransButtonSetting("ProjectAttachBTN");
    ProjectAttachBTN->setLabel(QObject::tr("Attach Defined Project"));
    ProjectAttachBTN->setHelpText("Attach the defined project, please note this may take several seconds"); 
    connect(ProjectAttachBTN, SIGNAL(pressed(QString)), this, SLOT(BtnPress(QString)));

    return(ProjectAttachBTN);
    
}


void MythBoincClientConfig::CreateProjectAccount()
{
    
    //VERBOSE(VB_IMPORTANT, "Attempting to lookup/create account");
    
    vector<string> commandString;
    redi::ipstream in;

    commandString.push_back(cmd);
    
    //host
    commandString.push_back("--host");
    commandString.push_back(ip);
    
    //password
    commandString.push_back("--passwd");
    commandString.push_back(pwd);
    
    //argument
    commandString.push_back("--create_account");
    
    //Project to lookup/create
    if(ProjectAttachURL->getValue().compare("CUSTOM")==0)
    {
        commandString.push_back(ProjectAttachCustURL->getValue());
    }
    else
    {
        commandString.push_back(projectDetails.at(ProjectAttachURL->getValue().toInt()).at(1)); 
    }
    
    //email for project account
    commandString.push_back(ProjectAttachEmail->getValue());
    
    //password for project account
    commandString.push_back(ProjectAttachPwd->getValue());
    
    //user name for account, I think many users can use the same account
    commandString.push_back(ProjectAttachUsr->getValue());

    //execute
    in.open("boinc_cmd", commandString, redi::pstreambuf::pstderr);
    
    string outLine;
    string accountKey;
 
    while(getline(in, outLine))
    {
        if(outLine.compare("poll status: operation in progress")!=0 && outLine.compare("status: Success")!=0)
        {
            if(outLine.compare(0,13, "account key: ")==0) 
            {
                accountKey = outLine.substr(13, outLine.size());
                AttachProject(accountKey);
            }
            else
            {
                DialogBox("Problem detected: "+outLine.substr(13, outLine.size())+"\nPlease check your details");  
            }
        }
    }

    //VERBOSE(VB_IMPORTANT, "DONE");
    in.close();  
    
}


void MythBoincClientConfig::AttachProject(string inAccountKey)
{
    
    //VERBOSE(VB_IMPORTANT, "Attempting to attach account");
    
    vector<string> commandString;
    redi::ipstream in;

    commandString.push_back(cmd);
    
    //host
    commandString.push_back("--host");
    commandString.push_back(ip);
    
    //password
    commandString.push_back("--passwd");
    commandString.push_back(pwd); 
    
    //argument
    commandString.push_back("--project_attach");
    
    //Project to lookup/create
    commandString.push_back(projectDetails.at(ProjectAttachURL->getValue().toInt()).at(1));
    
    //Account key
    commandString.push_back(inAccountKey);
    
    in.open("boinc_cmd", commandString, redi::pstreambuf::pstderr);
    
    string errLine;  
 
    getline(in.err(), errLine);
    if(!errLine.empty())
    {
        DialogBox("Problem detected: "+errLine);
    }
    else
    {
        DialogBox("Successfully attached: \n"+projectDetails.at(ProjectAttachURL->getValue().toInt()).at(0)+"\nThis project may not appear straight away");
    }
    
    in.close();
    
}


void MythBoincClientConfig::DialogBox(QString msg)
{
    
    MythPopupBox::showOkPopup
    (
        gContext->GetMainWindow(),
        QObject::tr("Event"),
        QString(QObject::tr(msg)),
        "OK"
    );
    
}


void MythBoincClientConfig::LoadDetachPage()
{
    
    VerticalConfigurationGroup *boincProjectDetachVCG = new VerticalConfigurationGroup(false);
    boincProjectDetachVCG->setLabel(QObject::tr("MythBOINC Project Detach for: "+ip));
    boincProjectDetachVCG->addChild(GetAttachedProjects()); 
    boincProjectDetachVCG->addChild(ProjectDetachBTN());
    
    this->addChild(boincProjectDetachVCG);
     
}

HostCheckBox *MythBoincClientConfig::ProjectDetachCBX(int ID)
{
    
    HostCheckBox *ProjectDetach = new HostCheckBox("ProjectDetach"+IntToString(ID));
    ProjectDetach->setLabel(QObject::tr("Detach"));
    ProjectDetach->setValue(false);
    ProjectDetach->setHelpText(QObject::tr("Detach this project"));
    
    return(ProjectDetach);
    
}


ButtonSetting *MythBoincClientConfig::ProjectDetachBTN()
{
       
    TransButtonSetting *ProjectDetachBTN = new TransButtonSetting("ProjectDetachBTN");   
    ProjectDetachBTN->setLabel(QObject::tr("Detach Selected Projects"));
    ProjectDetachBTN->setHelpText("Detaches selected projects, please note this may take several seconds"); 
    connect(ProjectDetachBTN, SIGNAL(pressed(QString)), this, SLOT(BtnPress(QString)));

    return(ProjectDetachBTN);
    
}

HostLineEdit *MythBoincClientConfig::ProjectDetachNameTXT(QString inName, int ID)
{
    
    HostLineEdit *ProjectName = new HostLineEdit("ProjectName"+IntToString(ID));
    ProjectName->setLabel(QObject::tr("Project Name"));
    ProjectName->setValue(inName);
    ProjectName->setEnabled(false);
    ProjectName->setHelpText(QObject::tr("The name of the attached project"));
    
    return(ProjectName);
    
}

vector<QString> MythBoincClientConfig::GetAttachedURLs()
{
    
    vector<QString> AttachedProjectURLs;
    vector<string> allResults;
    vector<string> commandString;
    redi::ipstream in;

    commandString.push_back(cmd);
    
    //host
    commandString.push_back("--host");
    commandString.push_back(ip);
    
    //password
    commandString.push_back("--passwd");
    commandString.push_back(pwd);

    //Argument to get info on projects
    commandString.push_back("--get_project_status");
    
    in.open("boinc_cmd", commandString);
    
    string resultLine;
    
    while (getline(in, resultLine)) 
    {
        allResults.push_back(resultLine);
    }

    for(unsigned i=0; i<allResults.size(); i++)
    {
        if(allResults.at(i).compare(0,15, "   master URL: ")==0)
        {  
            AttachedProjectURLs.push_back(allResults.at(i).substr(15, allResults.at(i).size()));
        }
    }
        
    in.close(); 

    return(AttachedProjectURLs);
    
}


VerticalConfigurationGroup *MythBoincClientConfig::GetAttachedProjects()
{
    
    VerticalConfigurationGroup *boincProjectVCG = new VerticalConfigurationGroup(false);
    
    vector<QString> projectURLs = GetAttachedURLs();

    for(unsigned i = 0; i < projectURLs.size(); i++)
    {
        HorizontalConfigurationGroup *boincProjectHCG = new HorizontalConfigurationGroup(false);
        ProjectNameTXTVEC.push_back(ProjectDetachNameTXT(projectURLs.at(i), i));
        boincProjectHCG->addChild(ProjectNameTXTVEC.at(i));
        
        ProjectDetachCBXVEC.push_back(ProjectDetachCBX(i));
        boincProjectHCG->addChild(ProjectDetachCBXVEC.at(i));
        boincProjectVCG->addChild(boincProjectHCG);
    }
    boincProjectVCG->save();
    
    return(boincProjectVCG);
    
}


void MythBoincClientConfig::DetachSelected()
{
    
    for(unsigned i=0; i<ProjectDetachCBXVEC.size(); i++)
    {
        if (ProjectDetachCBXVEC.at(i)->boolValue())
        {
            vector<string> commandString;
            redi::ipstream in;
            
            //command
            commandString.push_back(cmd);
            
            //host
            commandString.push_back("--host");
            commandString.push_back(ip);
    
            //password
            commandString.push_back("--passwd");
            commandString.push_back(pwd);
            
            //select project argument
            commandString.push_back("--project");
            
            //master project URL
            commandString.push_back(ProjectNameTXTVEC.at(i)->getValue());
            
            //argument to detach
            commandString.push_back("detach");
            
            string errLine;           
            in.open("boinc_cmd", commandString, redi::pstreambuf::pstderr);

            while(getline(in.err(), errLine))
            { 
                DialogBox("Problem detected: "+errLine);
            }
            in.close();
            
            ProjectNameTXTVEC.at(i)->setValue("detached");
            ProjectDetachCBXVEC.at(i)->setValue(false);
            ProjectDetachCBXVEC.at(i)->setEnabled(false);       
        }
    }
    
}


void MythBoincClientConfig::LoadMgrPage()
{
    
    VerticalConfigurationGroup *boincManagerVCG = new VerticalConfigurationGroup(false);
    boincManagerVCG->setLabel(QObject::tr("MythBOINC Manager Settings"));
    
    HorizontalConfigurationGroup *boincManagerHCG = new HorizontalConfigurationGroup(false);
        
    boincManagerVCG->addChild(BoincManagerURLTXT());
    boincManagerVCG->addChild(BoincManagerNameTXT());
    boincManagerVCG->addChild(BoincManagerPwdTXT());
    
    boincManagerHCG->addChild(AttachMgrBTN());
    boincManagerHCG->addChild(DetachMgrBTN());

    boincManagerVCG->addChild(boincManagerHCG);  
    
    this->addChild(boincManagerVCG);
    
}


HostLineEdit *MythBoincClientConfig::BoincManagerURLTXT()
{
    
    HostLineEdit *BoincManagerURL = new HostLineEdit("BoincManagerURL");
    BoincManagerURL->setLabel(QObject::tr("Manager URL"));
    BoincManagerURL->setValue("http://bam.boincstats.com/");
    BoincManagerURL->setHelpText(QObject::tr("Enter the Manager site's URL"));
    
    return(BoincManagerURL);
    
}

HostLineEdit *MythBoincClientConfig::BoincManagerNameTXT()
{
    
    HostLineEdit *BoincManagerName = new HostLineEdit("BoincManagerName");
    BoincManagerName->setLabel(QObject::tr("Manager Account Name"));
    BoincManagerName->setValue("MythBOINC");
    BoincManagerName->setHelpText(QObject::tr("Enter the Account Name"));
    
    return(BoincManagerName);
    
}


HostLineEdit *MythBoincClientConfig::BoincManagerPwdTXT()
{
    
    HostLineEdit *BoincManagerPwd = new HostLineEdit("BoincManagerPwd");
    BoincManagerPwd->setLabel(QObject::tr("Manager Account Password"));
    BoincManagerPwd->setValue("55233_7009226b656e509c5d6dd3eb82aa9728");
    BoincManagerPwd->setHelpText(QObject::tr("Enter the Account Password"));
    
    return(BoincManagerPwd);
    
}

ButtonSetting *MythBoincClientConfig::AttachMgrBTN()
{  
     
    TransButtonSetting *AttachMgrBTN = new TransButtonSetting("AttachMgrBTN");
    AttachMgrBTN->setLabel(QObject::tr("Attach"));
    connect(AttachMgrBTN, SIGNAL(pressed(QString)), this, SLOT(BtnPress(QString)));

    return(AttachMgrBTN);
    
}


ButtonSetting *MythBoincClientConfig::DetachMgrBTN()
{   
    
    TransButtonSetting *detachMgrBTN = new TransButtonSetting("DetachMgrBTN"); 
    detachMgrBTN->setLabel(QObject::tr("Detach"));
    connect(detachMgrBTN, SIGNAL(pressed(QString)), this, SLOT(BtnPress(QString)));

    return(detachMgrBTN);
    
}

void MythBoincClientConfig::BtnPress(QString ID)
{
    
    //VERBOSE(VB_IMPORTANT, "Manager button pressed: "+ID);

    if(ID.compare("ProjectDetachBTN")==0)
    {
        DetachSelected();
    }
    else if(ID.compare("ProjectAttachBTN")==0)
    {
        CreateProjectAccount();
    }
    
}

void MythBoincClientConfig::projectChanged(const QString &ID)
{
    if(projectDetails.at(ID.toInt()).at(1).compare("CUSTOM") == 0)
    {
       ProjectAttachCustURL->setEnabled(true);   
    }
    else
    {
       ProjectAttachCustURL->setEnabled(false);  
    }
    
    ProjectAttachURL->setHelpText(projectDetails.at(ID.toInt()).at(2));

}


/*************************************************************************************************/


#endif
